package cn.xianshu.service.impl;

import cn.xianshu.config.HighlightResultMapper;
import cn.xianshu.coursedto.CourseDoc;
import cn.xianshu.repository.CourseElasticsearchRepository;
import cn.xianshu.searchDto.CourseSearchDto;
import cn.xianshu.service.ICourseESService;
import cn.xianshu.util.PageList;
import cn.xianshu.vo.AggPageList;
import cn.xianshu.vo.TermsAggBucket;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class CourseESServiceImpl implements ICourseESService {

    @Autowired
    private CourseElasticsearchRepository repository;
    @Autowired
    private ElasticsearchTemplate template;
    @Autowired
    private HighlightResultMapper resultMapper;

    /**
     * 添加
     * @param doc
     */
    @Override
    public void save(CourseDoc doc) {
        repository.save(doc);
    }

    /**
     * 删除
     * @param id
     */
    @Override
    public void remove(Long id) {
        repository.deleteById(id);
    }

    /**
     * 搜索课程
     * @param dto :查询条件
     * @return ： 分页结果
     */
    @Override
    public PageList<CourseDoc> crumbs(CourseSearchDto dto) {
        // 查询条件构建器
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        // 排序
        if (StringUtils.isNotEmpty(dto.getSortField())){
            String sortField = "onlineTime";
            switch (dto.getSortField()){
                case "jg" : sortField = "price"; break;
                case "xl" : sortField = "saleCount"; break;
                case "pl" : sortField = "commentCount"; break;
                case "rq" : sortField = "viewCount"; break;
                case "xp" : sortField = "onlineTime"; break;
            }
            SortOrder sortOrder = SortOrder.DESC;
            if (dto.getSortField() != null && dto.getSortType().equalsIgnoreCase("asc")){
                sortOrder = SortOrder.ASC;
            }
            searchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(sortOrder));
        }
        // 分页
        searchQueryBuilder.withPageable(PageRequest.of(dto.getPage() - 1, dto.getRows()));
        // 条件
        // 组合查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 添加must
        if (StringUtils.isNotEmpty(dto.getKeyword())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", dto.getKeyword()));
        }
        // 添加filter
        // 课程分类Id
        if (null != dto.getCourseTypeId()){
            boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId", dto.getCourseTypeId()));
        }
        // 等级名字
        if (StringUtils.isNotEmpty(dto.getGradeName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName", dto.getGradeName()));
        }
        // 机构名字
        if (StringUtils.isNotEmpty(dto.getTenantName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("tenantName", dto.getTenantName()));
        }
        // 价格范围 最大
        if (null != dto.getPriceMax()){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        // 价格范围 最小
        if (null != dto.getPriceMin()){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }

        // 关联查询条件
        searchQueryBuilder.withQuery(boolQueryBuilder);
        // 高亮======================================================
        HighlightBuilder.Field field = new HighlightBuilder.Field("name")
                .preTags("<span style = 'color:red'>")
                .postTags("</span>");
        searchQueryBuilder.withHighlightFields(field);
        // 聚合======================================================
        // 等级聚合
        TermsAggregationBuilder gradeNameAgg = AggregationBuilders.terms("gradeNameAgg").field("gradeName");
        // 等级聚合
        TermsAggregationBuilder tenantNameAgg = AggregationBuilders.terms("tenantNameAgg").field("tenantName");
        searchQueryBuilder.addAggregation(gradeNameAgg).addAggregation(tenantNameAgg);
        // Page<CourseDoc> page = repository.search(searchQueryBuilder.build());
        AggregatedPage<CourseDoc> page = template.queryForPage(searchQueryBuilder.build(), CourseDoc.class, resultMapper);
        // 聚合结果
        Map<String, List<TermsAggBucket>> termsAggResult = new HashMap<>();
        // 聚合结果处理
        Map<String, Aggregation> aggregationMap = page.getAggregations().asMap();



        aggregationMap.keySet().forEach(key ->{
            // Buckets列表
            List<TermsAggBucket> termsAggBuckets = new ArrayList<>();
            // key 聚合名字
            // 值aggregation:
            StringTerms aggregation = (StringTerms)aggregationMap.get(key);


            aggregation.getBuckets().forEach(bucket -> {
                // 每一个bucket
                // 名字
                String name = bucket.getKey().toString();
                long docCount = bucket.getDocCount();
                // 一个bucket 转为TermsAggBucket对象
                termsAggBuckets.add(new TermsAggBucket(name, docCount));
            });


            // 加入到聚合结果
            termsAggResult.put(key, termsAggBuckets);
        });
        // 处理结果
        return new AggPageList(page.getTotalElements(), page.getContent(), termsAggResult);
    }


}
